import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

// 子组件 
// props是父组件向子组件传数据的中介
// state与props类似, 但是state是私有的, 并且完全受控于当前组件
// 用state实现记忆功能
/* class Square extends React.Component {
  render() {
    return (
      <button
        className="square"
        // 由于state对于每个组件来说是私有的, 因此我们不能直接通过Square来更新Board的state
        // 所以通过父组件传递返回值来实现
        // onClick={() => this.setState({ value: 'X' })}
        onClick={() => this.props.onClick()} // 此时调用的是Board中的handleClick方法
      >
        {this.props.value}
      </button>
    );
  }
} */
// Square中只含有一个render方法, 将其改写为函数组件更简单
function Square(props) {
  return (
    <button
      className="square"
      onClick={props.onClick} // onClick={()=>props.onClick()}的简写
    >
      {props.value}
    </button>
  );
}

// 父组件 
class Board extends React.Component {
  renderSquare(i) {
    return (
      <Square
        value={this.props.squares[i]}
        // 代表事件的监听 prop 命名为 on[Event], 将处理事件的监听方法命名为 handle[Event]
        onClick={() => this.props.onClick(i)}
      />
    );
  }

  render() {
    return (
      <div>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
        </div>
        <div className="board-row">
          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}
        </div>
        <div className="board-row">
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
        </div>
      </div>
    );
  }
}

// 父父组件
class Game extends React.Component {
  // 原在Board组件中的构造函数
  // 添加构造函数初始化state
  constructor(props) {
    super(props); // 构造函数必须以super(props)开头
    this.state = {
      // history保存历史版本
      history: [{
        squares: Array(9).fill(null),
      }],
      xIsNext: true, // 判断哪个玩家走棋, X为true, O为false
      stepNumber: 0, // 跳转的历史记录
    };
  }
  // state保存在Board中, 每当state发生变化, Square就重新渲染

  handleClick(i) {
    // 如果返回历史记录需要开启新历史, 丢弃旧历史
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    const current = history[history.length - 1]; // 当前状态
    // slice无参实现浅拷贝, 用来保存历史步骤
    const squares = current.squares.slice();
    // 出结果时 / Square已被填充时直接返回
    if (calculateWinner(squares) || squares[i]) return;
    squares[i] = this.state.xIsNext ? 'X' : 'O';
    this.setState({
      // 推入历史记录, 使用concat代替push不会改变原数组
      history: history.concat([{
        squares: squares,
      }]),
      xIsNext: !this.state.xIsNext, // 下一步时反转布尔值
      stepNumber: history.length,
    });
  }

  jumpTo(step) {
    this.setState({
      // React 不会更新setState方法中未提到的属性, history不会更新
      stepNumber: step,
      xIsNext: (step % 2) === 0, // 为偶数时需要重新走一轮
    });
  }

  render() {
    const history = this.state.history;
    const current = history[this.state.stepNumber];
    const winner = calculateWinner(current.squares);

    const moves = history.map((step, move) => {
      const desc = move ?
        'Go to move #' + move :
        'Go to game start';
      return (
        // 创建动态列表, 需要指定合适的key, 防止渲染出错
        <li key={move}>
          <button onClick={() => this.jumpTo(move)}>{desc}</button>
        </li>
      );
    });

    let status;
    if (winner) {
      status = `Winner:\n${winner}`;
    } else if (!winner && this.state.stepNumber === 9) {
      status = 'The game ended in a standoff.';
    } else {
      status = `Next player:\n${this.state.xIsNext ? 'X' : 'O'}`;
    }
    return (
      <div className="game">
        <div className="game-board">
          <Board
            squares={current.squares}
            onClick={(i) => this.handleClick(i)}
          />
        </div>
        <div className="game-info">
          <div>{status}</div>
          <ol>{moves}</ol>
        </div>
      </div>
    );
  }
}

function calculateWinner(squares) {
  const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];
  for (let i = 0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
      return squares[a];
    }
  }
  return null;
}
// ========================================

ReactDOM.render(
  <Game />,
  document.getElementById('root')
);
